package com.ponhu.ea2.goodsCenter.bms.api.controller;

import com.alibaba.excel.EasyExcelFactory;
import com.google.common.collect.Lists;
import com.ponhu.ea2.common.basic.model.PagedResult;
import com.ponhu.ea2.common.basic.model.ResponseBean;
import com.ponhu.ea2.constants.CommonConstant;
import com.ponhu.ea2.enums.ResponseCodeEnum;
import com.ponhu.ea2.goodsCenter.bms.api.utils.CommonUtils;
import com.ponhu.ea2.goodsCenter.bms.api.utils.CustomCellStyleHandler;
import com.ponhu.ea2.properties.GoodsProperties;
import com.ponhu.ea2.query.GoodsInfoQuery;
import com.ponhu.ea2.query.PickInventoryQuery;
import com.ponhu.ea2.service.facade.GoodsApiService;
import com.ponhu.ea2.service.facade.PickInventoryManageService;
import com.ponhu.ea2.support.exception.BusinessRuntimeException;
import com.ponhu.ea2.vo.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotBlank;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionException;
import java.util.stream.Collectors;

import static com.ponhu.ea2.constants.CommonConstant.USER_RULES_PICK_INVENTORY_SELECT;
import static com.ponhu.ea2.enums.ResponseCodeEnum.PARAMETER_IS_INCORRECT_800001;

/**
 * @author zhaokai
 */
@RefreshScope
@Slf4j
@RestController
@RequestMapping("/goods")
@Api(tags = "商品接口", description = "商品接口", value = "商品接口")
public class GoodsController {

    @DubboReference(version = "1.0.0", check = false)
    GoodsApiService goodsApiService;

    @DubboReference(version = "1.0.0", check = false, timeout = 15000, retries = -1, methods = {
            @Method(name = "getPickExportVoList", timeout = 1800000)
    })
    private PickInventoryManageService pickInventoryManageService;

    @Autowired
    private CommonUtils commonUtils;

    @Resource
    GoodsProperties goodsProperties;

    /**
     * 根据ID获取商品详情
     *
     * @param id
     * @return
     */
    @ApiOperation(value = "通过ID获取商品详情信息")
    @GetMapping("/getInfo")
    public ResponseBean<GoodsInfoVo> getInfo(@RequestParam(value = "id") Long id) {
        GoodsInfoVo goodsInfo = new GoodsInfoVo();
        if (null != id && id != 0L) {
            List<GoodsInfoVo> goodsInfoList = goodsApiService.getGoodsInfo(Lists.newArrayList(id));
            if (CollectionUtils.isNotEmpty(goodsInfoList)) {
                goodsInfo = goodsInfoList.get(0);
            }
        }
        return ResponseBean.ok(goodsInfo);
    }

    /**
     * 根据Code获取商品详情
     *
     * @param code
     * @return
     */
    @ApiOperation(value = "通过Code获取商品详情信息")
    @GetMapping("/getInfoByCode")
    public ResponseBean<GoodsInfoVo> getInfoByCode(@NotBlank(message = "货品编码不可为空") @RequestParam(value = "code") String code) {
        GoodsInfoVo goodsInfo = new GoodsInfoVo();
        if (StringUtils.isNotBlank(code)) {
            goodsInfo = goodsApiService.getGoodsInfoByCode(code);

        }
        return ResponseBean.ok(goodsInfo);
    }

    /**
     * 通过ID集合获取商品详情信息
     *
     * @param query 查询对象
     * @return List<GoodsInfoVo>
     */
    @ApiOperation(value = "通过ID集合获取商品详情信息")
    @PostMapping("/getInfoByGoodsIds")
    public ResponseBean<List<GoodsInfoVo>> getInfoByGoodsIds(@RequestBody GoodsInfoQuery query) {
        List<GoodsInfoVo> goodsInfo = new ArrayList<>();
        if (CollectionUtils.isEmpty(query.getGoodsIds())) {
            return ResponseBean.ok(goodsInfo);
        }
        goodsInfo = goodsApiService.getGoodsInfo(query.getGoodsIds());
        return ResponseBean.ok(goodsInfo);
    }

    @ApiImplicitParam(name = USER_RULES_PICK_INVENTORY_SELECT, value = "用户KPI货品权限(0:有权限;非0:无权限)", required = false, dataType = "String", paramType = "header")
    @ApiOperation(value = "选品列表查询")
    @PostMapping("/getPickInventoryListByCondition")
    public ResponseBean<PagedResult<PickInventoryVo>> getPickInventoryListByCondition(
            @Validated @RequestBody PickInventoryQuery query,
            @RequestHeader(value = USER_RULES_PICK_INVENTORY_SELECT, required = false) String pickInventoryRule) throws IOException {
        log.info("权限header：{}", pickInventoryRule);
        convertUserRules(query, pickInventoryRule);
        if (goodsProperties.getUseEsForPickInventory()) {
            log.info("选品列表查询-ES");
            return ResponseBean.ok(pickInventoryManageService.getPickInventoryListFromES(query));
        } else {
            log.info("选品列表查询-mysql");
            return ResponseBean.ok(pickInventoryManageService.getPickInventoryListByCondition(query));
        }
    }


    @ApiImplicitParam(name = USER_RULES_PICK_INVENTORY_SELECT, value = "用户KPI货品权限(0:有权限;非0:无权限)", required = false, dataType = "String", paramType = "header")
    @ApiOperation(value = "选品列表汇总结果查询")
    @PostMapping("/getPickInventoryStatisticsInfo")
    public ResponseBean<PickInventoryStatisticsVo> getPickInventoryStatisticsInfo(
            @Validated @RequestBody PickInventoryQuery query,
            @RequestHeader(value = USER_RULES_PICK_INVENTORY_SELECT, required = false) String pickInventoryRule) {
        log.info("权限header：{}", pickInventoryRule);
        convertUserRules(query, pickInventoryRule);
        if (goodsProperties.getUseEsForPickInventory()) {
            log.info("选品列表汇总结果查询-ES");
            return ResponseBean.ok(pickInventoryManageService.getPickInventoryStatisticsInfoFromES(query));
        } else {
            log.info("选品列表汇总结果查询-mysql");
            return ResponseBean.ok(pickInventoryManageService.getPickInventoryStatisticsInfo(query));
        }
    }

    /**
     * 根据货品ID查询选品详情
     *
     * @param inventoryId
     * @param pickInventoryRule
     * @return
     */
    @ApiOperation(value = "根据货品ID查询选品详情")
    @GetMapping("/getPickInventoryByInventoryId")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inventoryId", value = "货品Id",
                    dataType = "long", paramType = "query", required = true),
            @ApiImplicitParam(name = USER_RULES_PICK_INVENTORY_SELECT, value = "用户KPI货品权限(0:有权限;非0:无权限)", required = false, dataType = "String", paramType = "header")
    })
    public ResponseBean<PickInventoryDetailVo> getPickInventoryByInventoryId(
            @RequestParam Long inventoryId,
            @RequestHeader(value = USER_RULES_PICK_INVENTORY_SELECT, required = false) String pickInventoryRule) {
        log.info("权限header：{}", pickInventoryRule);
        String result = convertUserRules(null, pickInventoryRule);
        if (goodsProperties.getUseEsForPickInventory()) {
            log.info("根据货品ID查询选品详情-ES");
            return ResponseBean.ok(pickInventoryManageService.getPickInventoryByInventoryIdFromES(inventoryId, result));
        } else {
            log.info("根据货品ID查询选品详情-mysql");
            return ResponseBean.ok(pickInventoryManageService.getPickInventoryByInventoryId(inventoryId, result));
        }
    }

    @ApiOperation(value = "测试选品导出查询")
    @PostMapping("/testImportPickInventoryDataList")
    public ResponseBean<List<PickInventoryDetailVo>> importPickInventoryDataList(@Validated @RequestBody PickInventoryQuery query) {
        return ResponseBean.ok(pickInventoryManageService.exportPickInventoryDataList(query));
    }

    /**
     * 选品列表查询或勾选导出
     *
     * @param query
     * @param type
     * @param response
     * @param pickInventoryRule
     */
    @ApiOperation(value = "选品列表查询或勾选导出/type-导出类型：1-无图导出，2-有图导出，3-货品编码导出")
    @PostMapping("/pickExportExcel/{type}")
    public void pickExportExcel(@Validated @RequestBody PickInventoryQuery query,
                                @PathVariable("type") int type, HttpServletResponse response,
                                @RequestHeader(value = USER_RULES_PICK_INVENTORY_SELECT, required = false) String pickInventoryRule) {
        log.info("权限header：{}", pickInventoryRule);
        convertUserRules(query, pickInventoryRule);

        OutputStream output = null;
        List<PickExportVo> pickInventoryExportVoList = null;
        try {
            output = response.getOutputStream();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msexcel");
            String fileName = URLEncoder.encode("选品查询货品列表", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            long start = System.currentTimeMillis();
            if (type == 1) {
                pickInventoryExportVoList = pickInventoryManageService.getPickExportVoList(query, PickInventoryExportVo.class);
                EasyExcelFactory.write(output, PickInventoryExportVo.class)
//                        .registerWriteHandler(new CustomCellStyleHandler(Arrays.asList(1, 14, 15, 16, 23, 27)))
                        .sheet("货品列表")
                        .doWrite(pickInventoryExportVoList);
            }

            if (type == 2) {
                pickInventoryExportVoList = pickInventoryManageService
                        .getPickExportVoList(query, PickInventoryImgExportVo.class);
                EasyExcelFactory.write(output, PickInventoryImgExportVo.class)
//                        .registerWriteHandler(new CustomCellStyleHandler(Arrays.asList(2, 15, 16, 17, 24, 28)))
                        .sheet("货品列表")
                        .doWrite(commonUtils.getInputStreamParallel(pickInventoryExportVoList));
            }

            if (type == 3) {
                pickInventoryExportVoList = pickInventoryManageService.getPickExportVoList(query, PickCodeExportVo.class);
                EasyExcelFactory.write(output, PickCodeExportVo.class)
                        .sheet("货品列表")
                        .doWrite(pickInventoryExportVoList);
            }
//            System.out.printf("\033[32m exportExcel ===>> %s ms \033[0m\n", System.currentTimeMillis() - start);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (CollectionUtils.isNotEmpty(pickInventoryExportVoList)) {
                pickInventoryExportVoList.parallelStream().forEach(exportVo -> {
                    if (exportVo instanceof PickInventoryImgExportVo) {
                        InputStream inputStream = ((PickInventoryImgExportVo) exportVo).getInputStream();
                        if (ObjectUtils.isNotEmpty(inputStream)) {
                            try {
                                inputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
        }
    }

    /**
     * 选品列表编码导出
     *
     * @param uploadFile
     * @param type
     * @param response
     */
    @ApiOperation(value = "选品列表编码导出/type-导出类型：1-无图导出，2-有图导出")
    @PostMapping("/pickTxtExportExcel/{type}")
    public void pickTxtExportExcel(@Validated @RequestBody MultipartFile uploadFile,
                                   @PathVariable("type") int type, HttpServletResponse response,
                                   @RequestHeader(value = USER_RULES_PICK_INVENTORY_SELECT, required = false) String pickInventoryRule) {
        BufferedReader br = null;
        OutputStream output = null;
        List<PickExportVo> pickInventoryExportVoList = null;
        try {
            output = response.getOutputStream();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msexcel");
            String fileName = URLEncoder.encode("选品查询货品列表", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            long start = System.currentTimeMillis();
            Reader reader = new InputStreamReader(uploadFile.getInputStream());
            br = new BufferedReader(reader);
            List<String> inventoryCodeList = Lists.newArrayList();
            String inventoryCode;
            while ((inventoryCode = br.readLine()) != null) {
                inventoryCodeList.add(inventoryCode.trim());
            }
            PickInventoryQuery query = new PickInventoryQuery()
                    .setInventoryCodeList(inventoryCodeList);

            log.info("权限header：{}", pickInventoryRule);
            convertUserRules(query, pickInventoryRule);

            if (type == 1) {
                Map<String, PickInventoryExportVo> pickMap = pickInventoryManageService
                        .getPickExportVoList(query, PickInventoryExportVo.class).stream()
                        .collect(Collectors.toMap(vo -> ((PickInventoryExportVo) vo).getInventoryCode(), vo -> (PickInventoryExportVo) vo));

                pickInventoryExportVoList = inventoryCodeList.stream().map(code ->
                                pickMap.getOrDefault(code, new PickInventoryExportVo(code, "货品不存在")))
                        .collect(Collectors.toList());

                EasyExcelFactory.write(output, PickInventoryExportVo.class)
                        .registerWriteHandler(new CustomCellStyleHandler(Arrays.asList(1, 14, 15, 16, 23, 27)))
                        .sheet("货品列表")
                        .doWrite(pickInventoryExportVoList);
            }

            if (type == 2) {
                Map<String, PickInventoryImgExportVo> pickMap = pickInventoryManageService
                        .getPickExportVoList(query, PickInventoryImgExportVo.class).stream()
                        .collect(Collectors.toMap(vo -> ((PickInventoryImgExportVo) vo).getInventoryCode(), vo -> (PickInventoryImgExportVo) vo));

                pickInventoryExportVoList = inventoryCodeList.stream().map(code ->
                                pickMap.getOrDefault(code, new PickInventoryImgExportVo(code, "货品不存在")))
                        .collect(Collectors.toList());

                EasyExcelFactory.write(output, PickInventoryImgExportVo.class)
                        .registerWriteHandler(new CustomCellStyleHandler(Arrays.asList(2, 15, 16, 17, 24, 28)))
                        .sheet("货品列表")
                        .doWrite(commonUtils.getInputStreamParallel(pickInventoryExportVoList));
            }
//            System.out.printf("\033[32m exportExcel ===>> %s ms \033[0m\n", System.currentTimeMillis() - start);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (CollectionUtils.isNotEmpty(pickInventoryExportVoList)) {
                pickInventoryExportVoList.parallelStream().forEach(exportVo -> {
                    if (exportVo instanceof PickInventoryImgExportVo) {
                        InputStream inputStream = ((PickInventoryImgExportVo) exportVo).getInputStream();
                        if (ObjectUtils.isNotEmpty(inputStream)) {
                            try {
                                inputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                });
            }
        }
    }

    private String convertUserRules(PickInventoryQuery query, String pickInventoryRule) {
        if (query == null) {
            if ("0".equals(pickInventoryRule)) {
                return CommonConstant.YES_OR_NO.YES_STR;
            } else {
                return CommonConstant.YES_OR_NO.NO_STR;
            }
        }
        //0代表有权限，设置成yes
        if ("0".equals(pickInventoryRule)) {
            query.setPickInventoryRule(CommonConstant.YES_OR_NO.YES_STR);
        } else {
            query.setPickInventoryRule(CommonConstant.YES_OR_NO.NO_STR);
        }
        return null;
    }

    /**
     * 货品综合日志查询
     *
     * @param inventoryCode
     * @return
     */
    @ApiOperation(value = "货品综合日志查询")
    @GetMapping("/getOprLogsByInventoryCode")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inventoryCode", value = "货品编码",
                    dataType = "string", paramType = "query", required = true)
    })
    public ResponseBean<List<PhInventoryOprLogVo>> getOprLogsByInventoryCode(@RequestParam String inventoryCode) {
        if (StringUtils.isEmpty(inventoryCode))
            throw new BusinessRuntimeException(PARAMETER_IS_INCORRECT_800001);

            return ResponseBean.ok(goodsApiService.getOprLogsByInventoryCode(inventoryCode));
    }

}
